local Aloft = Aloft
if not Aloft then return end

-----------------------------------------------------------------------------

local AloftLevelText = Aloft:NewModule("LevelText", Aloft, "AceEvent-3.0", "AceHook-3.0", "AceTimer-3.0")

-----------------------------------------------------------------------------

AloftLevelText.namespace = "levelText"
AloftLevelText.defaults =
{
	profile =
	{
		enable				= true,
		font				= "Arial Narrow",
		fontSize			= 8,
		outline				= "OUTLINE",
		shadow				= false,
		point				= "RIGHT",
		relativeToPoint		= "RIGHT",
		offsetX				= 0,
		offsetY				= 0,
		showCreatureType	= false,
		showClassification	= false,
		showRace			= false,
		overrideText		= false,
		format				= "",
	},
}

-----------------------------------------------------------------------------

function AloftLevelText:UpdateAll()
	for aloftData in Aloft:IterateNameplates() do
		local levelTextRegion = aloftData.levelTextRegion
		local layoutFrame = aloftData.layoutFrame
		if layoutFrame then
			levelTextRegion:SetDrawLayer("OVERLAY")
			-- ChatFrame7:AddMessage("AloftLevelText:UpdateAll(): PrepareText " .. tostring(aloftData.name) .. "/" .. tostring(levelTextRegion) .. "/" .. tostring(self.db.profile.font) .. "/" .. tostring(self.db.profile.fontSize) .. "/" .. tostring(self.db.profile.outline) --[[.. "/" .. tostring(SML:Fetch("font", self.db.profile.font))]])
			self:PrepareText(levelTextRegion, self.db.profile)
			self:PlaceFrame(levelTextRegion, layoutFrame, self.db.profile, 0, 0)

			if self.db.profile.overrideText then
				if self.db.profile.format and self.db.profile.format ~= "" and (not self.textMethodData or not self.textMethod) then
					self.textMethodData = Aloft:CreateTag(self.db.profile.format, true)
					self.textMethod = self.textMethodData.method
				end
				levelTextRegion:SetText(self.textMethod(aloftData))
				levelTextRegion:Show()
			else
				levelTextRegion:SetText(aloftData.level or -1)
				if aloftData.level then
					levelTextRegion:Show()
				else
					levelTextRegion:Hide()
				end
			end

			return
		end
		levelTextRegion:Hide()
	end
end

function AloftLevelText:RegisterEvents()
	self:UnregisterAllEvents()
	self:UnregisterAllMessages()
	self:CancelAllTimers()

	-- self:RegisterEvent("PLAYER_TARGET_CHANGED", "UpdateLevelFromTarget")

	self:RegisterMessage("Aloft:SetupFrame", "SetupFrame")
	self:RegisterMessage("Aloft:SetAll", function(message, type, value)
										if AloftLevelText.db.profile[type] then
											AloftLevelText.db.profile[type] = value
											AloftLevelText:UpdateAll()
										end
									  end)

	if self.db.profile.enable then
		if self.db.profile.overrideText then
			if self.db.profile.format and self.db.profile.format ~= "" and (not self.textMethodData or not self.textMethod or not self.textMethodData.events) then
				self.textMethodData = Aloft:CreateTag(self.db.profile.format, true)
				self.textMethod = self.textMethodData.method
			end
			if self.textMethodData and self.textMethodData.events then
				for events in pairs(self.textMethodData.events) do
					-- ChatFrame7:AddMessage("AloftLevelText:RequiresData(): " .. register " .. tostring(events))
					self:RegisterMessage(events, "UpdateText")
				end
			end
			self:RegisterMessage("Aloft:OnNameplateShow", "PlaceAndUpdateLevelTextOnNameplateShow")
			self:RegisterMessage("Aloft:OnSetHealthBarColor", "UpdateText")
		else
			self:RegisterMessage("Aloft:OnNameplateShow", "PlaceLevelTextOnNameplateShow")
		end
	else
		self:RegisterMessage("Aloft:OnNameplateShow", "HideLevelTextOnNameplateShow")
	end
end

local dataRequiredList = { }
function AloftLevelText:RequiresData()
	self:RegisterEvents()

	if not self.db.profile.enable or not self.db.profile.overrideText then
		return
	end

	for i = 1,#dataRequiredList do
		dataRequiredList[i] = nil
	end

	if self.db.profile.format and self.db.profile.format ~= "" and (not self.textMethodData or not self.textMethod or not self.textMethodData.data) then
		self.textMethodData = Aloft:CreateTag(self.db.profile.format, true)
		self.textMethod = self.textMethodData.method
	end
	if self.textMethodData and self.textMethodData.data then
		for data in pairs(self.textMethodData.data) do
			-- ChatFrame7:AddMessage("AloftLevelText:RequiresData(): requires " .. tostring(data))
			table.insert(dataRequiredList, data)
		end
	end

	return unpack(dataRequiredList)
end

-----------------------------------------------------------------------------

function AloftLevelText:OnInitialize()
	if self.db ~= Aloft.AloftDB:GetNamespace(self.namespace, true) then self.db = Aloft.AloftDB:RegisterNamespace(self.namespace, self.defaults) end
end

function AloftLevelText:OnEnable()
	self:UpdateAll()
end

function AloftLevelText:OnDisable()
	self:UnregisterAllEvents()
	self:UnregisterAllMessages()
	self:CancelAllTimers()

	for aloftData in Aloft:IterateNameplates() do
		local nameplateFrame = aloftData.nameplateFrame
		local levelTextRegion = aloftData.levelTextRegion

		levelTextRegion:ClearAllPoints()
		levelTextRegion:SetPoint("CENTER", nameplateFrame, "BOTTOMRIGHT", -13.331, 10.288)
		levelTextRegion:SetFont(NAMEPLATE_FONT, 11)
		levelTextRegion:SetShadowOffset(1, -1)
		levelTextRegion:SetAlpha(1)
		levelTextRegion:SetText(aloftData.level or -1)
	end
	self:UnhookAll()
end

function AloftLevelText:SetupFrame(message, aloftData)
	local levelTextRegion = aloftData.levelTextRegion
	local layoutFrame = Aloft:AcquireLayoutFrame(aloftData)

	-- if aloftData.name == "[invalid]" or not self.db or not self.db.profile or not self.db.profile.font or not self.db.profile.fontSize or not self.db.profile.outline then
		-- ChatFrame7:AddMessage("AloftLevelText:SetupFrame(): " .. tostring(aloftData.name) .. "/" .. tostring(levelTextRegion) .. "/" .. tostring(self.db) .. "/" .. tostring(self.db.profile) .. "/" .. tostring(self.db.profile.font) .. "/" .. tostring(self.db.profile.fontSize) .. "/" .. tostring(self.db.profile.outline) --[[.. "/" .. tostring(SML:Fetch("font", self.db.profile.font))]])
		-- ChatFrame7:AddMessage("AloftLevelText:SetupFrame(): " .. debugstack())
	-- end

	levelTextRegion:SetDrawLayer("OVERLAY")
	-- ChatFrame7:AddMessage("AloftLevelText:SetupFrame(): PrepareText " .. tostring(aloftData.name) .. "/" .. tostring(levelTextRegion) .. "/" .. tostring(self.db) .. "/" .. tostring(self.db.profile) .. "/" .. tostring(self.db.profile.font) .. "/" .. tostring(self.db.profile.fontSize) .. "/" .. tostring(self.db.profile.outline) --[[.. "/" .. tostring(SML:Fetch("font", self.db.profile.font))]])
	self:PrepareText(levelTextRegion, self.db.profile)
	self:PlaceFrame(levelTextRegion, layoutFrame, self.db.profile, 0, 0)

	self:Hook(levelTextRegion, "GetText", "GetLevelTextRegionText", true)
	self:Hook(levelTextRegion, "SetText", "SetLevelTextRegionText", true)
end

function AloftLevelText:GetLevelTextRegionText(this)
	local level = this.aloftData.level
	if level then return level end
	return self.hooks[this].GetText(this)
end

function AloftLevelText:SetLevelTextRegionText(this, text)
	--[[
	local aloftData = this.aloftData
	
	local level = text:match("%d+")
	if level and level ~= tostring(aloftData.level) then
		aloftData.level = tonumber(level)
	end

	if self.db.profile.format and self.db.profile.format ~= "" and (not self.textMethodData or not self.textMethod) then
		self.textMethodData = Aloft:CreateTag(self.db.profile.format, true)
		self.textMethod = self.textMethodData.method
	end
	]]

	self.hooks[this].SetText( this, text )
end

function AloftLevelText:UpdateText(message, aloftData)
	-- ChatFrame7:AddMessage("AloftLevelText:RequiresData(): " .. tostring(aloftData.name) .. "/" ..
	--	("%s:0x%02x%02x%02x"):format(tostring(aloftData.class), floor(aloftData.originalHealthBarR*255), floor(aloftData.originalHealthBarG*255), floor(aloftData.originalHealthBarB*255)))
	if self.db.profile.format and self.db.profile.format ~= "" and (not self.textMethodData or not self.textMethod) then
		self.textMethodData = Aloft:CreateTag(self.db.profile.format, true)
		self.textMethod = self.textMethodData.method
	end
	aloftData.levelTextRegion:SetText(self.textMethod(aloftData))
end

function AloftLevelText:PlaceAndUpdateLevelTextOnNameplateShow(message, aloftData)
	local levelTextRegion = aloftData.levelTextRegion

	if aloftData.isBoss then
		levelTextRegion:SetTextColor(1, 0, 0)
	end

	levelTextRegion:SetDrawLayer("OVERLAY")
	-- ChatFrame7:AddMessage("AloftLevelText:PlaceAndUpdateLevelTextOnNameplateShow(): PrepareText " .. tostring(aloftData.name) .. "/" .. tostring(levelTextRegion) .. "/" .. tostring(self.db.profile.font) .. "/" .. tostring(self.db.profile.fontSize) .. "/" .. tostring(self.db.profile.outline) --[[.. "/" .. tostring(SML:Fetch("font", self.db.profile.font))]])
	self:PrepareText(levelTextRegion, self.db.profile)
	self:PlaceFrame(levelTextRegion, aloftData.layoutFrame, self.db.profile, 0, 0)
	levelTextRegion:Show()

	self:UpdateText(message, aloftData)
end

function AloftLevelText:PlaceLevelTextOnNameplateShow(message, aloftData)
	local levelTextRegion = aloftData.levelTextRegion

	levelTextRegion:SetDrawLayer("OVERLAY")
	-- ChatFrame7:AddMessage("AloftLevelText:PlaceLevelTextOnNameplateShow(): PrepareText " .. tostring(aloftData.name) .. "/" .. tostring(levelTextRegion) .. "/" .. tostring(self.db.profile.font) .. "/" .. tostring(self.db.profile.fontSize) .. "/" .. tostring(self.db.profile.outline) --[[.. "/" .. tostring(SML:Fetch("font", self.db.profile.font))]])
	self:PrepareText(levelTextRegion, self.db.profile)
	self:PlaceFrame(levelTextRegion, aloftData.layoutFrame, self.db.profile, 0, 0)
end

function AloftLevelText:HideLevelTextOnNameplateShow(message, aloftData)
	aloftData.levelTextRegion:Hide()
end

-----------------------------------------------------------------------------

function AloftLevelText:UpdateLevelFromTarget()
	self:UpdateFromUnit("target")
end

function AloftLevelText:UpdateFromUnit(unitid)
	if UnitIsPlayer(unitid) then return end

	local level = UnitLevel(unitid)
	if level == -1 then level = nil end

	self:ScheduleTimer(function(level) AloftLevelText:UpdateUnitLevel(level) end, 0.0, level) -- next frame
end

function AloftLevelText:UpdateUnitLevel(level)
	local aloftData = Aloft:GetTargetNameplate()
	if (aloftData) then
		self:AssignValues(aloftData, level)
	end
end

function AloftLevelText:AssignValues(aloftData, level)
	if aloftData.level ~= level then
		local oldLevel = aloftData.level
		aloftData.level = level
		self:SendMessage("Aloft:OnUnitLevelChanged", aloftData, oldLevel)
	end
end

-----------------------------------------------------------------------------
